﻿using System;

namespace Liphofra.Mvvm.Validation
{
    /// <summary>
    /// A base implementation for common validation rule behavior.
    /// Contains helper methods to e.g. get access to the value of a property by property name easily.
    /// </summary>
    public class ValidationRuleBase : IValidationRule
    {
        /// <summary>
        /// Validates the specified target.
        /// </summary>
        /// <typeparam name="T">The type of the target.</typeparam>
        /// <param name="target">The target to validate.</param>
        /// <returns>
        /// A single validation result indicating the result of the validation.
        /// </returns>
        public virtual ValidationResult Validate<T>(T target)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Validates the specified property of the target.
        /// </summary>
        /// <typeparam name="T">The type of the target.</typeparam>
        /// <param name="target">The target to validate.</param>
        /// <param name="propertyName">The name of the property to validate.</param>
        /// <returns>
        /// A single validation result indicating the result of the validation.
        /// </returns>
        public virtual ValidationResult ValidateProperty<T>(T target, string propertyName)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// A convenience method for derived classes that gets the value of a property on the given target.
        /// </summary>
        /// <typeparam name="TPropertyType">The type of the property.</typeparam>
        /// <param name="target">The target to get the property value from.</param>
        /// <param name="propertyName">The name of the property.</param>
        /// <returns>The name of the property or the default value of the property type of the target or property name are <c>null</c>.</returns>
        protected static TPropertyType GetPropertyValue<TPropertyType>(object target, string propertyName)
        {
            if (target == null || string.IsNullOrEmpty(propertyName))
            {
                return default(TPropertyType);
            }

            var type = target.GetType();
            var propertyInfo = type.GetProperty(propertyName);
            var actualPropertyType = propertyInfo.PropertyType;
            var expectedPropertyType = typeof(TPropertyType);
            
            // type check
            if (!expectedPropertyType.IsAssignableFrom(actualPropertyType))
            {
                return default(TPropertyType);
            }

            var result = (TPropertyType)propertyInfo.GetValue(target);
            return result;
        }
    }
}